﻿Public Class Document

    Public Process As Process
    Public Orientation As PageOrientation

    Event PrintStarted()
    Event TabSelected(ByVal sender As Object, ByVal Index As String)

    Dim m_Active As Boolean
    Dim Canvas As New RectangleF(0, 0, 0, 0)
    Property Active() As Boolean
        Get
            Return m_Active
        End Get
        Set(ByVal Value As Boolean)
            m_Active = Value
            ToolStrip.Visible = Value
            BtnSayfa.Visible = Value
            If Not Value Then
                Clear()
                Panel.Invalidate()
            End If
        End Set
    End Property

    Dim Info As PrintInfo

    Dim m_Zoom As PageZoom
    Property Zoom() As PageZoom
        Get
            Return m_Zoom
        End Get
        Set(ByVal Value As PageZoom)
            m_Zoom = Value
            BtnPage.Checked = Zoom = PageZoom.WholePage
            BtnWidth.Checked = Zoom = PageZoom.PageWidth
            BtnText.Checked = Zoom = PageZoom.TextWidth
            Recalculate()
        End Set
    End Property

    ReadOnly Property PrinterAspect() As Single
        Get
            Return PrintDocument.DefaultPageSettings.PrintableArea.Width / PrintDocument.DefaultPageSettings.PrintableArea.Height
        End Get
    End Property

    Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
        Region = New Region(New Rectangle(3, 3, Width - 6, Height - 6))
        MyBase.OnResize(e)
    End Sub

    Sub Recalculate()
        Select Case Zoom
            Case PageZoom.WholePage
                Dim ScrollMargin As Integer = 8
                Dim NewWidth = Panel.Width - ScrollMargin * 2
                Dim MaxHeight = Panel.Height - ScrollMargin * 2
                Dim NewHeight = NewWidth / PrinterAspect
                If NewHeight > MaxHeight Then
                    NewHeight = MaxHeight
                    NewWidth = NewHeight * PrinterAspect
                End If
                Canvas.Size = New Size(NewWidth, NewHeight)
                Canvas.Location = New Point((Panel.Width - NewWidth) / 2, (Panel.Height - NewHeight) / 2)
                ScrollHeight = NewHeight
            Case PageZoom.PageWidth, PageZoom.TextWidth
                Dim ScrollMargin As Integer = If(Zoom = PageZoom.TextWidth, -48, 8)
                Dim NewWidth = Panel.Width - ScrollMargin * 2
                Canvas.Location = New Point(ScrollMargin, ScrollMargin)
                Canvas.Size = New Size(NewWidth, NewWidth / PrinterAspect)
                ScrollHeight = Canvas.Height + 2 * ScrollMargin
        End Select
        Panel.Invalidate()
    End Sub

    Property ScrollHeight() As Integer
        Get
            Return ScrollBar.Maximum
        End Get
        Set(ByVal Value As Integer)
            ScrollBar.Enabled = Value > Panel.Height
            If Not ScrollBar.Enabled Then ScrollBar.Value = 0 : Exit Property
            ScrollBar.Maximum = Value
            ScrollBar.LargeChange = Panel.Height
            ScrollBar.SmallChange = ScrollBar.LargeChange / 16
            If ScrollBar.Value > Value - ScrollBar.LargeChange Then ScrollBar.Value = Value - ScrollBar.LargeChange
        End Set
    End Property

    Sub Start()
        Dim PrintableArea As RectangleF = PrintDocument.DefaultPageSettings.Bounds
        PrintableArea.Inflate(-PrintableArea.Width / 15, -PrintableArea.Width / 15)
        PrintableArea.Width -= PrintDocument.DefaultPageSettings.HardMarginX * 2
        PrintableArea.Height -= PrintDocument.DefaultPageSettings.HardMarginY * 2
        Info = New PrintInfo(PrintableArea, PrintDocument.PrinterSettings.CreateMeasurementGraphics)
        For Each Section As Section In Sections
            Section.Print(Info)
        Next
        PageNo = 1
        Zoom = PageZoom.TextWidth
    End Sub

    Private Sub PrintDocument_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument.PrintPage
        Info.Pages(PrinterPage).Render(e.Graphics, 0, 0)
        PrinterPage += 1
        e.HasMorePages = PrinterPage < Info.Pages.Count
    End Sub

    Private Sub Panel_MouseWheel(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseWheel
        If Not ScrollBar.Enabled Then Exit Sub
        Dim v As Single = ScrollBar.Value - e.Delta / 1500 * ScrollBar.LargeChange
        If v < ScrollBar.Minimum Then v = ScrollBar.Minimum
        If v > ScrollBar.Maximum - ScrollBar.LargeChange Then v = ScrollBar.Maximum - ScrollBar.LargeChange
        ScrollBar.Value = v
    End Sub

    Dim m_PageNo As Integer
    Property PageNo() As Integer
        Get
            Return m_PageNo
        End Get
        Set(ByVal Value As Integer)
            m_PageNo = Value
            SetButtonInfo()
            ScrollBar.Value = ScrollBar.Minimum
            Panel.Invalidate(New Rectangle(Canvas.Location.X, Canvas.Location.Y, Canvas.Size.Width, Canvas.Size.Height))
            'Panel.Invalidate()
        End Set
    End Property

    Private Sub SetButtonInfo()
        BtnFirst.Enabled = PageNo > 1
        BtnLast.Enabled = PageNo < Info.Pages.Count
        BtnPrev.Enabled = PageNo > 1
        BtnNext.Enabled = PageNo < Info.Pages.Count
        MnuFirst.Enabled = BtnFirst.Enabled
        MnuLast.Enabled = BtnLast.Enabled
        MnuPrev.Enabled = BtnPrev.Enabled
        MnuNext.Enabled = BtnNext.Enabled
        BtnSayfa.Text = "Sayfa: " & PageNo & "/" & Info.Pages.Count
        BtnSayfa.Visible = Info.Pages.Count > 0
        ToolStrip.Invalidate()
    End Sub

    Dim Bitmap As Bitmap
    Private Sub Panel_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel.Paint
        If Info Is Nothing Then Exit Sub
        If Info.Pages.Count = 0 Then Exit Sub
        With e.Graphics
            .SmoothingMode = Drawing2D.SmoothingMode.HighQuality
            .PixelOffsetMode = Drawing2D.PixelOffsetMode.None
            Dim RR As New Rectangle(Canvas.Location.X, Canvas.Location.Y, Canvas.Size.Width, Canvas.Size.Height)
            RR.Offset(0, -ScrollBar.Value)
            If Zoom <> PageZoom.TextWidth Then
                RR.Inflate(4, 4)
                For i As Integer = 1 To 4
                    FillRoundRect(e.Graphics, RR, New SolidBrush(Color.FromArgb(16, Color.Black)), (7 - i) * 2)
                    RR.Inflate(-1, -1)
                Next
            End If
            .InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
            With PrintDocument.DefaultPageSettings
                If Bitmap Is Nothing OrElse Bitmap.Tag <> PageNo Then
                    Bitmap = Info.Render(PageNo, .PaperSize.Width, .PaperSize.Height, .HardMarginX, .HardMarginY)
                    Bitmap.Tag = PageNo
                End If
                e.Graphics.DrawImage(Bitmap, RR, 0, 0, Bitmap.Width, Bitmap.Height, GraphicsUnit.Pixel)
            End With
            .SmoothingMode = Drawing2D.SmoothingMode.None
        End With
    End Sub

    Private Sub ToolStrip_ItemClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles ToolStrip.ItemClicked
        Select Case e.ClickedItem.Name
            Case "BtnFirst" : PageNo = 1
            Case "BtnPrev" : PageNo -= 1
            Case "BtnNext" : PageNo += 1
            Case "BtnLast" : PageNo = Info.Pages.Count
            Case "BtnPage" : Zoom = PageZoom.WholePage
            Case "BtnWidth" : Zoom = PageZoom.PageWidth
            Case "BtnText" : Zoom = PageZoom.TextWidth
            Case "BtnPrint" : If Not e.ClickedItem.Pressed Then ShowPrint()
            Case "BtnSetup" : ShowSetup()
            Case "BtnHide" : ToolStrip.Visible = False
        End Select
    End Sub

    Private Sub ShowSetup()
        PageSetupDialog.ShowDialog()
    End Sub

    Dim OnlyCurrent As Boolean
    Dim PrinterPage As Integer
    Private Sub ShowPrint(Optional ByVal OnlyCurrentPage As Boolean = False)
        RaiseEvent PrintStarted()
        OnlyCurrent = OnlyCurrentPage
        PrinterPage = 0
        If OnlyCurrent Then PrinterPage = PageNo
        PrintDocument.DefaultPageSettings.Landscape = Orientation = PageOrientation.Landscape
        PrintDocument.Print()
    End Sub

    Private Sub Document_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
        Recalculate()
    End Sub

    Private Sub ScrollBar_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ScrollBar.ValueChanged
        Panel.Invalidate()
    End Sub

End Class

Public Class PrintInfo
    Public PrintableArea As RectangleF
    Public CursorY As Integer
    Public Pages As New List(Of PrintPage)
    Public Graphics As Graphics

    Sub New(ByVal PrintableArea As RectangleF, ByVal G As Graphics)
        Me.PrintableArea = PrintableArea
        CursorY = PrintableArea.Top
        Pages.Add(New PrintPage)
        Graphics = G
    End Sub

    Function Reserve(ByVal h As Integer) As Boolean
        If CursorY + h > PrintableArea.Bottom Then
            CursorY = PrintableArea.Top
            Pages.Add(New PrintPage)
            Return True
        End If
    End Function

    Sub EndPage()
        If Pages(Pages.Count - 1).Items.Count = 0 Then Exit Sub
        Pages.Add(New PrintPage)
        CursorY = PrintableArea.Top
    End Sub

    Sub Progress(ByVal h As Integer)
        CursorY += h
    End Sub

    Sub Cleanup()
        Do Until Pages(Pages.Count - 1).Items.Count > 0
            Pages.RemoveAt(Pages.Count - 1)
        Loop
    End Sub


    Sub Add(ByVal Rect As Rectangle, ByVal Tram As String)
        Pages(Pages.Count - 1).Items.Add(New PageRectItem(Rect, Tram))
    End Sub

    Sub Add(ByVal Item As PageItem)
        Pages(Pages.Count - 1).Items.Add(Item)
    End Sub


    Dim PageNo As Integer = -1
    Dim Bitmap As Bitmap
    Function Render(ByVal PageNo As Integer, ByVal Width As Integer, ByVal Height As Integer, ByVal HMx As Integer, ByVal HMy As Integer) As Bitmap
        Dim Quality As Integer = 1200
        If PageNo = Me.PageNo Then Return Bitmap
        Me.PageNo = PageNo
        Bitmap = New Bitmap(CInt(Quality / Height * Width), Quality)
        Dim G As Graphics = Graphics.FromImage(Bitmap)
        G.Clear(Color.White)
        G.ScaleTransform(Bitmap.Width / Width, Bitmap.Height / Height)
        G.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
        G.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
        G.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
        Pages(PageNo - 1).Render(G, HMx, HMy)
        G.ResetTransform()
        G.PixelOffsetMode = Drawing2D.PixelOffsetMode.None
        Return Bitmap
    End Function

    Class PrintPage
        Public Items As New List(Of PageItem)

        Sub Render(ByVal G As Graphics, ByVal x As Integer, ByVal y As Integer)
            For Each Item As PageItem In Items
                Item.Render(G, x, y)
            Next
        End Sub

    End Class

End Class

Public MustInherit Class PageItem
    Protected Rect As Rectangle

    MustOverride Sub Render(ByVal G As Graphics, ByVal x As Integer, ByVal y As Integer)

End Class

Public Class PageTextItem
    Inherits PageItem

    Dim Font As Font
    Dim Text As String
    Dim Alignment As String
    Dim Wrap As Boolean

    Sub New(ByVal Rect As Rectangle, ByVal Font As Font, ByVal Text As String, ByVal Alignment As String)
        Me.Rect = Rect
        Me.Font = Font
        Me.Text = Text
        Me.Alignment = Alignment
    End Sub

    Public Overrides Sub Render(ByVal G As System.Drawing.Graphics, ByVal x As Integer, ByVal y As Integer)
        Dim R As Rectangle = Rect
        R.Offset(x, y)
        Dim Format As StringFormat = StrFormat("l", "c")
        For i As Integer = 1 To Len(Alignment)
            Select Case Mid(Alignment, i, 1)
                Case "c" : Format.Alignment = StringAlignment.Center
                Case "r" : Format.Alignment = StringAlignment.Far
                Case "b" : Format.LineAlignment = StringAlignment.Far
                Case "t" : Format.LineAlignment = StringAlignment.Near
                Case "w" : Wrap = True
            End Select
        Next i
        Dim Font As Font = Me.Font
        If Not Wrap Then
            Do
                If Int(G.MeasureString(Text, Font, R.Width, Format).Height) <= Me.Font.Height Then Exit Do
                Font = New Font(Font.Name, Font.Size - 0.5, Font.Style, Font.Unit)
            Loop
        End If
        'Dim Gray As Integer = 255 - Len(Tram) * 32
        'G.DrawRectangle(New Pen(Color.Blue), R)
        If Mid(Text, 1, 1) = "[" AndAlso Mid(Text, 3, 1) = "]" Then
            R.Height = Font.GetHeight(G)
            R.Inflate(-(R.Width - R.Height) / 2, 0)
            R.Inflate(-R.Height / 6, -R.Height / 6)
            'If R.Width < R.Height Then R.Height = R.Width Else R.Width = R.Height
            G.DrawRectangle(Pens.Black, R)
            R.Inflate(-R.Height / 6, -R.Height / 6)
            Select Case Mid(Text, 2, 1)
                Case "/" : G.DrawLine(Pens.Black, R.Left, R.Bottom - R.Height \ 3, R.Left + R.Width \ 3, R.Bottom) : G.DrawLine(Pens.Black, R.Left + R.Width \ 3, R.Bottom, R.Right, R.Top)
                Case "x" : G.DrawLine(Pens.Black, R.Left, R.Top, R.Right, R.Bottom) : G.DrawLine(Pens.Black, R.Left, R.Bottom, R.Right, R.Top)
            End Select
        Else
            G.DrawString(Text, Font, Brushes.Black, R, Format)
        End If
    End Sub

End Class

Public Class PageImageItem
    Inherits PageItem

    Dim Image As String

    Sub New(ByVal Rect As Rectangle, ByVal Image As String)
        MyBase.Rect = Rect
        Me.Image = Image
    End Sub

    Public Overrides Sub Render(ByVal G As System.Drawing.Graphics, ByVal x As Integer, ByVal y As Integer)
        Dim R As Rectangle = Rect
        R.Offset(x, y)
        G.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
        G.DrawImage(My.Resources.ResourceManager.GetObject(Image), R)
    End Sub

End Class

Public Class PageRectItem
    Inherits PageItem

    Dim Tram As String

    Sub New(ByVal Rect As Rectangle, ByVal Tram As String)
        Me.Rect = Rect
        Me.Tram = Tram
    End Sub

    Public Overrides Sub Render(ByVal G As System.Drawing.Graphics, ByVal x As Integer, ByVal y As Integer)
        Dim R As Rectangle = Rect
        R.Offset(x, y)
        Dim Gray As Integer = 255 - Len(Tram) * 32
        G.FillRectangle(New SolidBrush(Color.FromArgb(Gray, Gray, Gray)), R)
    End Sub

End Class

Public Enum PageOrientation
    Portrait
    Landscape
    SaglikKarnesi
End Enum

Public Enum PageZoom
    WholePage
    PageWidth
    TextWidth
End Enum
